package com.easylinkin.linkappapi.meterbilling.service.impl;

import com.alibaba.fastjson.JSON;
import com.easylinkin.linkappapi.meterbilling.entity.ext.ThirdPayResult;
import com.easylinkin.linkappapi.meterbilling.service.ThirdPayService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;

import cn.hutool.crypto.digest.MD5;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

/**
 * class info :
 *
 * @author liuqihang
 * @date 2021/8/2 16:39
 */
@Service
@Slf4j
public class ThirdPayServiceImpl implements ThirdPayService {

    @Value("${wechat.pay.third_url}")
    public String thirdUrl;

    @Value("${wechat.pay.attach}")
    public String attach;

    @Value("${wechat.pay.backUrl}")
    public String backUrl;

    @Value("${wechat.pay.body}")
    public String body;

    @Value("${wechat.pay.orgId}")
    public String orgId;

    @Value("${wechat.pay.subjectId}")
    public String subjectId;

    @Value("${wechat.pay.token}")
    public String token;

    @Value("${wechat.pay.ask_order_url}")
    public String askOrderUrl;

    @Value("${wechat.pay.sign}")
    public String sign;

    @Override
    public ThirdPayResult createOrder(BigDecimal money) throws Exception {
        //业务方支付参数
        Map<String, Object> paramsMap = createParamsMap(money);

        //组装加密sign
        String sign = getSign(paramsMap,orgId,token);
        paramsMap.put("sign", sign);

        //发起请求
        OkHttpClient client = new OkHttpClient().newBuilder().build();
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, JSON.toJSON(paramsMap).toString());
        Request request = new Request.Builder()
                .url(thirdUrl + "/weixin/initPayOrder?orgId=" + orgId + "&subjectId=" + subjectId)
                .method("POST", body).addHeader("Content-Type", "application/json").build();
        Response response = client.newCall(request).execute();
        String result = response.body().string();
        log.info("调用LinkThings创建订单结果：{}" + result);
        ThirdPayResult thirdPayResult = JSON.parseObject(result, ThirdPayResult.class);
        return thirdPayResult;
    }

    public Map<String, Object> createParamsMap(BigDecimal money){
        Map<String, Object> paramsMap = new HashMap<>(16);
        paramsMap.put("attach", attach);
        paramsMap.put("backUrl", backUrl);
        paramsMap.put("body", body);
        paramsMap.put("payAmount", money);
        return paramsMap;
    }

    public static String getSign(Map<String, Object> param, String orgId, String token) {
            TreeMap<String, Object> treeMp = new TreeMap<>(param);
            String orgSign = MD5.create().digestHex(orgId + token);
            String urlStr = getUrlParamsByMapObj(treeMp);
            String clientSign = MD5.create().digestHex(urlStr + orgSign);
            return clientSign;
    }

    public static String getUrlParamsByMapObj(Map<String, Object> map) {
        if (map == null) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            sb.append(entry.getKey() + "=" + entry.getValue());
            sb.append("&");
        }
        String s = sb.toString();
        if (s.endsWith("&")) {
            s = StringUtils.substringBeforeLast(s, "&");
        }
        return s;
    }

    public String getClientSign(Map<String, Object> param,String orgSign) {
        Map<String, Object> params = new HashMap<>(param);
        // 去除sign的所有参数计算最终签名
        params.remove("sign");
        TreeMap<String, Object> treeMp = new TreeMap<>(params);
        String urlStr = getUrlParamsByMapObj(treeMp);
        // 加盐加密 MD5 hash加密
        String clientSign = MD5.create().digestHex(urlStr + orgSign);
        return clientSign;
    }

    @Override
    public Map<String, Object> getParams(Map<String, String[]> requestParams) {
        Map<String, Object> params = new HashMap<>();
        try {
            for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
                String name = iter.next();
                String[] values = requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                params.put(name, valueStr);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return params;
    }
    @Override
    public Boolean checkSign(Map<String, Object> params) {
        // 1.生成商户token签名
        String orgSign = MD5.create().digestHex(orgId + token);
        // 2.组合参数 共同生成最终签名
        String clientSign = getClientSign(params,orgSign);
        log.info("clientSign=" + clientSign);
        // 3.获取请求参数签名
        String sign = String.valueOf(params.get("sign"));
        // 4.比对签名
        if(sign.equals(clientSign)){
            return true;
        }
        return false;
    }

    @Override
    public String askOrderStatus(String orderNo) {
        Map<String, Object> paramsMap = new HashMap<>(16);
        paramsMap.put("outTradeNo", orderNo);
        String result = null;
        try{
            CloseableHttpClient httpclient = HttpClients.createDefault();
            RequestConfig requestConfig = RequestConfig.custom()
                    .setSocketTimeout(60000)
                    .setConnectTimeout(60000)
                    .setConnectionRequestTimeout(60000)
                    .build();
            final String requestUrl = askOrderUrl.concat("?orgId=").concat(orgId).concat("&sign=").concat(sign).concat("&outTradeNo=").concat(orderNo);
            HttpGet httpGet = new HttpGet(requestUrl);
            httpGet.setConfig(requestConfig);
            httpGet.setHeader("Content-Type", "application/json");

            CloseableHttpResponse httpResponse = httpclient.execute(httpGet);
            HttpEntity entity = httpResponse.getEntity();
            if (entity != null) {
                result = EntityUtils.toString(entity, "UTF-8");
            }
            log.debug("订单询问发起：{}, 响应结果：{}", requestUrl, result);
        }catch(Exception ex){
            ex.printStackTrace();
        }
        return result;
    }
}
